home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume14 / jove4.9 / part12 < prev    next >
Encoding:
Internet Message Format  |  1988-04-26  |  30.4 KB

  1. Subject:  v14i068:  Jove, an emacs variant, version 4.9, Part12/21
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Jonathan Payne <jpayne@cs.rochester.edu>
  7. Posting-number: Volume 14, Issue 68
  8. Archive-name: jove4.9/part12
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then unpack
  12. # it by saving it into a file and typing "sh file".  To overwrite existing
  13. # files, type "sh file -c".  You can also feed this as standard input via
  14. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  15. # will see the following message at the end:
  16. #        "End of archive 12 (of 21)."
  17. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  18. if test -f './io.c' -a "${1}" != "-c" ; then 
  19.   echo shar: Will not clobber existing file \"'./io.c'\"
  20. else
  21. echo shar: Extracting \"'./io.c'\" \(28324 characters\)
  22. sed "s/^X//" >'./io.c' <<'END_OF_FILE'
  23. X/***************************************************************************
  24. X * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
  25. X * is provided to you without charge, and with no warranty.  You may give  *
  26. X * away copies of JOVE, including sources, provided that this notice is    *
  27. X * included in all the files.                                              *
  28. X ***************************************************************************/
  29. X#include "jove.h"
  30. X#include "io.h"
  31. X#include "termcap.h"
  32. X
  33. X#ifdef IPROCS
  34. X#   include <signal.h>
  35. X#endif
  36. X
  37. X#ifdef MAC
  38. X#    include "mac.h"
  39. X#else
  40. X#    include <sys/stat.h>
  41. X#endif
  42. X
  43. X#ifdef UNIX
  44. X#include <sys/file.h>
  45. X#endif
  46. X
  47. X#ifdef MSDOS
  48. X#include <fcntl.h>
  49. X#include <io.h>
  50. X#ifdef CHDIR
  51. X#include <direct.h>
  52. X#include <dos.h>
  53. X#endif
  54. X#endif /* MSDOS */
  55. X#include <errno.h>
  56. X
  57. X#ifdef MAC
  58. X#    undef private
  59. X#    define private
  60. X#endif
  61. X
  62. X#ifdef    LINT_ARGS
  63. private struct block
  64. X    * b_unlink(struct block *),
  65. X    * lookup(short);
  66. X
  67. private char
  68. X    * dbackup(char *, char *, char),
  69. X#if defined(MSDOS) && defined(CHDIR)
  70. X    * fixpath(char *),
  71. X#endif
  72. X    * getblock(disk_line, int);
  73. X    
  74. private void
  75. X#if defined(MSDOS) && defined(CHDIR)
  76. X    abspath(char *, char *),
  77. X#endif
  78. X    fake_blkio(struct block *, int (*)()),
  79. X    LRUunlink(struct block *),
  80. X    real_blkio(struct block *, int (*)());
  81. X
  82. private int
  83. X#if defined(MSDOS) && defined(CHDIR)
  84. X    Dchdir(char *),
  85. X#endif    
  86. X    dfollow(char *, char *);
  87. X    
  88. X#else
  89. private struct block
  90. X    * b_unlink(),
  91. X    * lookup();
  92. X
  93. private char
  94. X    * dbackup(),
  95. X#if defined(MSDOS) && defined(CHDIR)
  96. X    * fixpath(),
  97. X#endif
  98. X    * getblock();
  99. X
  100. private void
  101. X#if defined(MSDOS) && defined(CHDIR)
  102. X    abspath(),
  103. X#endif
  104. X    fake_blkio(),
  105. X    LRUunlink(),
  106. X    real_blkio();
  107. X
  108. private int
  109. X#if defined(MSDOS) && defined(CHDIR)
  110. X    Dchdir(),
  111. X#endif    
  112. X    dfollow();
  113. X#endif    /* LINT_ARGS */
  114. X
  115. X#ifdef MAC
  116. X#    undef private
  117. X#    define private static
  118. X#endif
  119. X
  120. X
  121. X#ifndef W_OK
  122. X#   define W_OK    2
  123. X#   define F_OK    0
  124. X#endif
  125. X
  126. long    io_chars;        /* number of chars in this open_file */
  127. int    io_lines;        /* number of lines in this open_file */
  128. X
  129. X#if defined(VMUNIX)||defined(MSDOS)
  130. char    iobuff[LBSIZE],
  131. X    genbuf[LBSIZE],
  132. X    linebuf[LBSIZE];
  133. X#else
  134. char    *iobuff,
  135. X    *genbuf,
  136. X    *linebuf;
  137. X#endif
  138. X
  139. X#ifdef BACKUPFILES
  140. int    BkupOnWrite = 0;
  141. X#endif
  142. X
  143. void
  144. close_file(fp)
  145. File    *fp;
  146. X{
  147. X    if (fp) {
  148. X        if (fp->f_flags & F_TELLALL)
  149. X            add_mess(" %d lines, %D characters.",
  150. X                 io_lines,
  151. X                 io_chars);
  152. X        f_close(fp);
  153. X    }
  154. X}
  155. X
  156. X/* Write the region from line1/char1 to line2/char2 to FP.  This
  157. X   never CLOSES the file since we don't know if we want to. */
  158. X
  159. int    EndWNewline = 1;
  160. X
  161. void
  162. putreg(fp, line1, char1, line2, char2, makesure)
  163. register File    *fp;
  164. Line    *line1,
  165. X    *line2;
  166. X{
  167. X    register int    c;
  168. X    register char    *lp;
  169. X
  170. X    if (makesure)
  171. X        (void) fixorder(&line1, &char1, &line2, &char2);
  172. X    while (line1 != line2->l_next) {
  173. X        lp = lcontents(line1) + char1;
  174. X        if (line1 == line2) {
  175. X            fputnchar(lp, (char2 - char1), fp);
  176. X            io_chars += (char2 - char1);
  177. X        } else while (c = *lp++) {
  178. X            putc(c, fp);
  179. X            io_chars += 1;
  180. X        }
  181. X        if (line1 != line2) {
  182. X            io_lines += 1;
  183. X            io_chars += 1;
  184. X#ifdef MSDOS
  185. X            putc('\r', fp);
  186. X#endif /* MSDOS */
  187. X            putc('\n', fp);
  188. X        }
  189. X        line1 = line1->l_next;
  190. X        char1 = 0;
  191. X    }
  192. X    flush(fp);
  193. X}
  194. X
  195. void
  196. read_file(file, is_insert)
  197. char    *file;
  198. X{
  199. X    Bufpos    save;
  200. X    File    *fp;
  201. X    if (!is_insert) {
  202. X        curbuf->b_ntbf = 0;
  203. X        set_ino(curbuf);
  204. X    }
  205. X    fp = open_file(file, iobuff, F_READ, !COMPLAIN, !QUIET);
  206. X    if (fp == NIL) {
  207. X        if (!is_insert && errno == ENOENT)
  208. X            s_mess("(new file)");
  209. X        else
  210. X            s_mess(IOerr("open", file));
  211. X        return;
  212. X    }
  213. X    DOTsave(&save);
  214. X    dofread(fp);
  215. X    if (is_insert && io_chars > 0) {
  216. X        modify();
  217. X        set_mark();
  218. X    }
  219. X    SetDot(&save);
  220. X    getDOT();
  221. X    close_file(fp);
  222. X}
  223. X
  224. void
  225. dofread(fp)
  226. register File    *fp;
  227. X{
  228. X    char    end[LBSIZE];
  229. X    int    xeof = 0;
  230. X    Line    *savel = curline;
  231. X    int    savec = curchar;
  232. X    extern disk_line    f_getputl();
  233. X
  234. X    strcpy(end, linebuf + curchar);
  235. X    xeof = f_gets(fp, linebuf + curchar, LBSIZE - curchar);
  236. X    SavLine(curline, linebuf);
  237. X    if (!xeof) do {
  238. X        curline = listput(curbuf, curline);
  239. X        xeof = f_getputl(curline, fp);
  240. X    } while (!xeof);
  241. X    getDOT();
  242. X    linecopy(linebuf, (curchar = strlen(linebuf)), end);
  243. X    SavLine(curline, linebuf);
  244. X    IFixMarks(savel, savec, curline, curchar);
  245. X}
  246. X
  247. void
  248. SaveFile()
  249. X{
  250. X    if (IsModified(curbuf)) {
  251. X        if (curbuf->b_fname == 0)
  252. X            WriteFile();
  253. X        else {
  254. X            filemunge(curbuf->b_fname);
  255. X#ifndef MAC
  256. X#ifndef MSDOS    /* not sure - kg - */
  257. X            chk_mtime(curbuf, curbuf->b_fname, "save");
  258. X#endif /* MSDOS */
  259. X#endif /* MAC */
  260. X            file_write(curbuf->b_fname, 0);
  261. X            unmodify();
  262. X        }
  263. X    } else
  264. X        message("No changes need to be written.");
  265. X}
  266. X
  267. char    *HomeDir;    /* home directory */
  268. int    HomeLen = -1;    /* length of home directory string */
  269. X
  270. X#ifndef CHDIR
  271. X
  272. char *
  273. pr_name(fname, okay_home)
  274. char    *fname;
  275. X{
  276. X    if (fname == 0)
  277. X        return 0;
  278. X
  279. X    if (okay_home == YES && strncmp(fname, HomeDir, HomeLen) == 0) {
  280. X        static char    name_buf[100];
  281. X
  282. X        sprintf(name_buf, "~%s", fname + HomeLen);
  283. X        return name_buf;
  284. X    }
  285. X
  286. X    return fname;
  287. X}
  288. X
  289. X#else
  290. X
  291. X#define NDIRS    5
  292. X
  293. private char    *DirStack[NDIRS] = {0};
  294. private int    DirSP = 0;    /* Directory stack pointer */
  295. X#define PWD    (DirStack[DirSP])
  296. X
  297. char *
  298. pwd()
  299. X{
  300. X    return PWD;
  301. X}
  302. X
  303. char *
  304. pr_name(fname, okay_home)
  305. char    *fname;
  306. X{
  307. X    int    n;
  308. X
  309. X    if (fname == 0)
  310. X        return 0;
  311. X    n = numcomp(fname, PWD);
  312. X
  313. X    if ((PWD[n] == 0) &&    /* Matched to end of PWD */
  314. X        (fname[n] == '/'))
  315. X        return fname + n + 1;
  316. X
  317. X    if (okay_home == YES && strcmp(HomeDir, "/") != 0 && strncmp(fname, HomeDir, HomeLen) == 0) {
  318. X        static char    name_buf[100];
  319. X
  320. X        sprintf(name_buf, "~%s", fname + HomeLen);
  321. X        return name_buf;
  322. X    }
  323. X
  324. X    return fname;    /* return entire path name */
  325. X}
  326. X
  327. extern unsigned int fmask;
  328. X
  329. Chdir()
  330. X{
  331. X    char    dirbuf[FILESIZE];
  332. X
  333. X#ifdef MSDOS
  334. X    fmask = 0x10;
  335. X#endif    
  336. X    (void) ask_file((char *) 0, PWD, dirbuf);
  337. X#ifdef MSDOS
  338. X    fmask = 0x13;
  339. X    if (Dchdir(dirbuf) == -1)
  340. X#else
  341. X    if (chdir(dirbuf) == -1)
  342. X#endif
  343. X    {
  344. X        s_mess("cd: cannot change into %s.", dirbuf);
  345. X        return;
  346. X    }
  347. X    UpdModLine = YES;
  348. X    setCWD(dirbuf);
  349. X    prCWD();
  350. X#ifdef MAC
  351. X    Bufchange++;
  352. X#endif
  353. X}
  354. X
  355. X#ifdef UNIX
  356. X#ifndef JOB_CONTROL
  357. char *
  358. getwd()
  359. X{
  360. X    Buffer    *old = curbuf;
  361. X    char    *ret_val;
  362. X
  363. X    SetBuf(do_select((Window *) 0, "pwd-output"));
  364. X    curbuf->b_type = B_PROCESS;
  365. X    (void) UnixToBuf("pwd-output", NO, 0, YES, "/bin/pwd", (char *) 0);
  366. X    ToFirst();
  367. X    ret_val = sprint(linebuf);
  368. X    SetBuf(old);
  369. X    return ret_val;
  370. X}
  371. X#endif
  372. X#endif /* UNIX */
  373. X
  374. setCWD(d)
  375. char    *d;
  376. X{
  377. X    if (PWD == 0)
  378. X        PWD = malloc((unsigned) strlen(d) + 1);
  379. X    else {
  380. X        extern char    *ralloc();
  381. X
  382. X        PWD = ralloc(PWD, strlen(d) + 1);
  383. X    }
  384. X    strcpy(PWD, d);
  385. X}
  386. X
  387. getCWD()
  388. X{
  389. X    char    *cwd;
  390. X#ifndef MSDOS
  391. X#ifdef JOB_CONTROL
  392. X    extern char    *getwd();
  393. X    char    pathname[FILESIZE];
  394. X#endif
  395. X#else
  396. X    extern char    *getcwd();
  397. X    char    pathname[FILESIZE];
  398. X#endif
  399. X
  400. X#ifndef MSDOS
  401. X    cwd = getenv("CWD");
  402. X    if (cwd == 0)
  403. X        cwd = getenv("PWD");
  404. X    if (cwd == 0)
  405. X#ifdef JOB_CONTROL
  406. X        cwd = getwd(pathname);
  407. X#else
  408. X        cwd = getwd();
  409. X#endif
  410. X#else /* MSDOS */
  411. X        cwd = fixpath(getcwd(pathname, FILESIZE));
  412. X#endif /* MSDOS */
  413. X
  414. X    setCWD(cwd);
  415. X}    
  416. X
  417. prDIRS()
  418. X{
  419. X    register int    i;
  420. X
  421. X    s_mess(": %f ");
  422. X    for (i = DirSP; i >= 0; i--)
  423. X        add_mess("%s ", pr_name(DirStack[i], YES));
  424. X}
  425. X
  426. prCWD()
  427. X{
  428. X    s_mess(": %f => \"%s\"", PWD);
  429. X}
  430. X
  431. Pushd()
  432. X{
  433. X    char    *newdir,
  434. X        dirbuf[FILESIZE];
  435. X
  436. X#ifdef MSDOS
  437. X    fmask = 0x10;
  438. X#endif    
  439. X    newdir = ask_file((char *) 0, NullStr, dirbuf);
  440. X#ifdef MSDOS
  441. X    fmask = 0x13;
  442. X#endif    
  443. X    UpdModLine = YES;
  444. X    if (*newdir == 0) {    /* Wants to swap top two entries */
  445. X        char    *old_top;
  446. X
  447. X        if (DirSP == 0)
  448. X            complain("pushd: no other directory.");
  449. X        old_top = PWD;
  450. X        DirStack[DirSP] = DirStack[DirSP - 1];
  451. X        DirStack[DirSP - 1] = old_top;
  452. X#ifdef MSDOS
  453. X        (void) Dchdir(PWD);
  454. X#else
  455. X        (void) chdir(PWD);
  456. X#endif
  457. X    } else {
  458. X#ifdef MSDOS
  459. X        if (Dchdir(dirbuf) == -1) {
  460. X#else
  461. X        if (chdir(dirbuf) == -1) {
  462. X#endif
  463. X            s_mess("pushd: cannot change into %s.", dirbuf);
  464. X            return;
  465. X        }
  466. X
  467. X        if (DirSP + 1 >= NDIRS)
  468. X            complain("pushd: full stack; max of %d pushes.", NDIRS);
  469. X        DirSP += 1;
  470. X        setCWD(dirbuf);
  471. X    }
  472. X    prDIRS();
  473. X}
  474. X
  475. Popd()
  476. X{
  477. X    if (DirSP == 0)
  478. X        complain("popd: directory stack is empty.");
  479. X    UpdModLine = YES;
  480. X    free(PWD);
  481. X    PWD = 0;
  482. X    DirSP -= 1;
  483. X#ifdef MSDOS
  484. X    (void) Dchdir(PWD);    /* If this doesn't work, we's in deep shit. */
  485. X#else
  486. X    (void) chdir(PWD);    /* If this doesn't work, we's in deep shit. */
  487. X#endif
  488. X    prDIRS();
  489. X}
  490. X
  491. private char *
  492. dbackup(base, offset, c)
  493. register char    *base,
  494. X        *offset,
  495. X        c;
  496. X{
  497. X    while (offset > base && *--offset != c)
  498. X        ;
  499. X    return offset;
  500. X}
  501. X
  502. private
  503. dfollow(file, into)
  504. char    *file,
  505. X    *into;
  506. X{
  507. X    char    *dp,
  508. X#ifdef MSDOS
  509. X        filefix[FILESIZE],
  510. X#endif        
  511. X        *sp;
  512. X
  513. X#ifndef MSDOS
  514. X    if (*file == '/') {        /* Absolute pathname */
  515. X        strcpy(into, "/");
  516. X        file += 1;
  517. X    } else
  518. X        strcpy(into, PWD);
  519. X#else
  520. X    abspath(file, filefix);        /* convert to absolute pathname */
  521. X    strcpy(into, filefix);        /* and forget about drives    */
  522. X    into[3] = 0;
  523. X    into = &(into[2]);
  524. X    file = &(filefix[3]);
  525. X#endif    
  526. X    dp = into + strlen(into);
  527. X
  528. X    sp = file;
  529. X    do {
  530. X        if (*file == 0)
  531. X            break;
  532. X        if (sp = index(file, '/'))
  533. X            *sp = 0;
  534. X        if (strcmp(file, ".") == 0)
  535. X            ;    /* So it will get to the end of the loop */
  536. X        else if (strcmp(file, "..") == 0) {
  537. X            *(dp = dbackup(into, dp, '/')) = 0;
  538. X            if (dp == into)
  539. X                strcpy(into, "/"), dp = into + 1;
  540. X        } else {
  541. X            if (into[strlen(into) - 1] != '/')
  542. X                (void) strcat(into, "/"), dp += 1;
  543. X            (void) strcat(into, file);
  544. X            dp += strlen(file);    /* stay at the end */
  545. X        }
  546. X        file = sp + 1;
  547. X    } while (sp != 0);
  548. X}
  549. X
  550. X#endif /* CHDIR */
  551. X
  552. X#ifdef UNIX
  553. private
  554. get_hdir(user, buf)
  555. register char    *user,
  556. X        *buf;
  557. X{
  558. X    char    fbuf[LBSIZE],
  559. X        pattern[100];
  560. X    register int    u_len;
  561. X    File    *fp;
  562. X
  563. X    u_len = strlen(user);
  564. X    fp = open_file("/etc/passwd", fbuf, F_READ, COMPLAIN, QUIET);
  565. X    sprintf(pattern, "%s:[^:]*:[^:]*:[^:]*:[^:]*:\\([^:]*\\):", user);
  566. X    while (f_gets(fp, genbuf, LBSIZE) != EOF)
  567. X        if ((strncmp(genbuf, user, u_len) == 0) &&
  568. X            (LookingAt(pattern, genbuf, 0))) {
  569. X            putmatch(1, buf, FILESIZE);
  570. X            close_file(fp);
  571. X            return;
  572. X        }
  573. X    f_close(fp);
  574. X    complain("[unknown user: %s]", user);
  575. X}
  576. X#endif /* UNIX */
  577. X
  578. void
  579. PathParse(name, intobuf)
  580. char    *name,
  581. X    *intobuf;
  582. X{
  583. X    char    localbuf[FILESIZE];
  584. X
  585. X    intobuf[0] = localbuf[0] = '\0';
  586. X    if (*name == '\0')
  587. X        return;
  588. X    if (*name == '~') {
  589. X        if (name[1] == '/' || name[1] == '\0') {
  590. X            strcpy(localbuf, HomeDir);
  591. X            name += 1;
  592. X#if !(defined(MSDOS) || defined(MAC))    /* may add for mac in future */
  593. X        } else {
  594. X            char    *uendp = index(name, '/'),
  595. X                unamebuf[30];
  596. X
  597. X            if (uendp == 0)
  598. X                uendp = name + strlen(name);
  599. X            name = name + 1;
  600. X            null_ncpy(unamebuf, name, uendp - name);
  601. X            get_hdir(unamebuf, localbuf);
  602. X            name = uendp;
  603. X#endif 
  604. X        }
  605. X    } 
  606. X#ifndef MSDOS
  607. X     else if (*name == '\\')
  608. X        name += 1;
  609. X#endif /* MSDOS */
  610. X    (void) strcat(localbuf, name);
  611. X#ifdef CHDIR
  612. X    dfollow(localbuf, intobuf);
  613. X#else
  614. X    strcpy(intobuf, localbuf);
  615. X#endif
  616. X}
  617. X
  618. void
  619. filemunge(newname)
  620. char    *newname;
  621. X{
  622. X    struct stat    stbuf;
  623. X
  624. X    if (newname == 0)
  625. X        return;
  626. X    if (stat(newname, &stbuf))
  627. X        return;
  628. X#ifndef MSDOS
  629. X    if (((stbuf.st_dev != curbuf->b_dev) ||
  630. X         (stbuf.st_ino != curbuf->b_ino)) &&
  631. X#else /* MSDOS */
  632. X    if ( /* (stbuf.st_ino != curbuf->b_ino) && */
  633. X#endif /* MSDOS */
  634. X#ifndef MAC
  635. X        ((stbuf.st_mode & S_IFMT) != S_IFCHR) &&
  636. X#endif
  637. X        (strcmp(newname, curbuf->b_fname) != 0)) {
  638. X        rbell();
  639. X        confirm("\"%s\" already exists; overwrite it? ", newname);
  640. X    }
  641. X}
  642. X
  643. void
  644. WrtReg()
  645. X{
  646. X    DoWriteReg(NO);
  647. X}
  648. X
  649. void
  650. AppReg()
  651. X{
  652. X    DoWriteReg(YES);
  653. X}
  654. X
  655. int    CreatMode = DFLT_MODE;
  656. X
  657. void
  658. DoWriteReg(app)
  659. X{
  660. X    char    fnamebuf[FILESIZE],
  661. X        *fname;
  662. X    Mark    *mp = CurMark();
  663. X    File    *fp;
  664. X
  665. X    /* Won't get here if there isn't a Mark */
  666. X    fname = ask_file((char *) 0, (char *) 0, fnamebuf);
  667. X
  668. X#ifdef BACKUPFILES
  669. X    if (app == NO) {
  670. X        filemunge(fname);
  671. X
  672. X        if (BkupOnWrite)
  673. X            file_backup(fname);
  674. X    }
  675. X#else
  676. X    if (!app)
  677. X        filemunge(fname);
  678. X#endif
  679. X
  680. X    fp = open_file(fname, iobuff, app ? F_APPEND : F_WRITE, COMPLAIN, !QUIET);
  681. X    putreg(fp, mp->m_line, mp->m_char, curline, curchar, YES);
  682. X    close_file(fp);
  683. X}
  684. X
  685. int    OkayBadChars = 0;
  686. X
  687. void
  688. WriteFile()
  689. X{
  690. X    char    *fname,
  691. X        fnamebuf[FILESIZE];
  692. X#ifdef MAC
  693. X    if(Macmode) {
  694. X        if(!(fname = pfile(fnamebuf))) return;
  695. X    }
  696. X    else
  697. X#endif /* MAC */
  698. X
  699. X    fname = ask_file((char *) 0, curbuf->b_fname, fnamebuf);
  700. X    /* Don't allow bad characters when creating new files. */
  701. X    if (!OkayBadChars && strcmp(curbuf->b_fname, fnamebuf) != 0) {
  702. X#ifdef UNIX
  703. X        static char    *badchars = "!$^&*()~`{}\"'\\|<>? ";
  704. X#endif /* UNIX */
  705. X#ifdef MSDOS
  706. X        static char    *badchars = "*|<>? ";
  707. X#endif /* MSDOS */
  708. X#ifdef MAC
  709. X        static char *badchars = ":";
  710. X#endif /* MAC */
  711. X        register char    *cp = fnamebuf;
  712. X        register int    c;
  713. X
  714. X        while (c = *cp++ & CHARMASK)    /* avoid sign extension... */
  715. X            if (c < ' ' || c == '\177' || index(badchars, c))
  716. X                complain("'%p': bad character in filename.", c);
  717. X    }
  718. X
  719. X#ifndef MAC
  720. X#ifndef MSDOS
  721. X    chk_mtime(curbuf, fname, "write");
  722. X#endif /* MSDOS */
  723. X#endif /* MAC */
  724. X    filemunge(fname);
  725. X    curbuf->b_type = B_FILE;      /* in case it wasn't before */
  726. X    setfname(curbuf, fname);
  727. X    file_write(fname, 0);
  728. X    unmodify();
  729. X}
  730. X
  731. X/* Open file FNAME supplying the buffer IO routine with buffer BUF.
  732. X   HOW is F_READ, F_WRITE or F_APPEND.  IFBAD == COMPLAIN means that
  733. X   if we fail at opening the file, call complain.  LOUDNESS says
  734. X   whether or not to print the "reading ..." message on the message
  735. X   line.
  736. X
  737. X   NOTE:  This opens the pr_name(fname, NO) of fname.  That is, FNAME
  738. X      is usually an entire pathname, which can be slow when the
  739. X      pathname is long and there are lots of symbolic links along
  740. X      the way (which has become very common in my experience).  So,
  741. X      this speeds up opens file names in the local directory.  It
  742. X      will not speed up things like "../scm/foo.scm" simple because
  743. X      by the time we get here that's already been expanded to an
  744. X      absolute pathname.  But this is a start.
  745. X   */
  746. X
  747. File *
  748. open_file(fname, buf, how, ifbad, loudness)
  749. register char    *fname;
  750. char    *buf;
  751. register int    how;
  752. X{
  753. X    register File    *fp;
  754. X
  755. X    io_chars = 0;
  756. X    io_lines = 0;
  757. X
  758. X    fp = f_open(pr_name(fname, NO), how, buf, LBSIZE);
  759. X    if (fp == NIL) {
  760. X                message(IOerr((how == F_READ) ? "open" : "create", fname));
  761. X        if (ifbad == COMPLAIN)
  762. X            complain((char *) 0);
  763. X    } else {
  764. X        int    readonly = FALSE;
  765. X#ifndef MAC
  766. X        if (access(pr_name(fname, NO), W_OK) == -1 && errno != ENOENT)
  767. X            readonly = TRUE;
  768. X#endif                 
  769. X        if (loudness != QUIET) {
  770. X            fp->f_flags |= F_TELLALL;
  771. X            f_mess("\"%s\"%s", pr_name(fname, YES),
  772. X                   readonly ? " [Read only]" : NullStr);
  773. X        }
  774. X    }
  775. X    return fp;
  776. X}
  777. X
  778. X#ifndef MSDOS
  779. X/* Check to see if the file has been modified since it was
  780. X   last written.  If so, make sure they know what they're
  781. X   doing.
  782. X
  783. X   I hate to use another stat(), but to use confirm we gotta
  784. X   do this before we open the file.
  785. X
  786. X   NOTE: This stats FNAME after converting it to a path-relative
  787. X     name.  I can't see why this would cause a problem ...
  788. X   */
  789. X
  790. chk_mtime(thisbuf, fname, how)
  791. Buffer    *thisbuf;
  792. char    *fname,
  793. X    *how;
  794. X{
  795. X    struct stat    stbuf;
  796. X    Buffer    *b;
  797. X        char    *mesg = "Shall I go ahead and %s anyway? ";
  798. X
  799. X    if ((thisbuf->b_mtime != 0) &&        /* if we care ... */
  800. X        (b = file_exists(fname)) &&        /* we already have this file */
  801. X        (b == thisbuf) &&            /* and it's the current buffer */
  802. X        (stat(pr_name(fname, NO), &stbuf) != -1) &&    /* and we can stat it */
  803. X        (stbuf.st_mtime != b->b_mtime)) {    /* and there's trouble. */
  804. X            rbell();
  805. X        redisplay();    /* Ring that bell! */
  806. X            TOstart("Warning", TRUE);
  807. X            Typeout("\"%s\" now saved on disk is not what you last", pr_name(fname, YES));
  808. X        Typeout("visited or saved.  Probably someone else is editing");
  809. X        Typeout("your file at the same time.");
  810. X            if (how) {
  811. X            Typeout("");
  812. X            Typeout("Type \"y\" if I should %s, anyway.", how);
  813. X                f_mess(mesg, how);
  814. X        }
  815. X            TOstop();
  816. X            if (how)
  817. X                confirm(mesg, how);
  818. X    }
  819. X}
  820. X
  821. X#endif /* MSDOS */
  822. X
  823. void
  824. file_write(fname, app)
  825. char    *fname;
  826. X{
  827. X    File    *fp;
  828. X
  829. X#ifdef BACKUPFILES
  830. X    if (!app && BkupOnWrite)
  831. X        file_backup(fname);
  832. X#endif
  833. X
  834. X    fp = open_file(fname, iobuff, app ? F_APPEND : F_WRITE, COMPLAIN, !QUIET);
  835. X
  836. X    if (EndWNewline) {    /* Make sure file ends with a newLine */
  837. X        Bufpos    save;
  838. X
  839. X        DOTsave(&save);
  840. X        ToLast();
  841. X        if (length(curline))    /* Not a blank Line */
  842. X            LineInsert(1);
  843. X        SetDot(&save);
  844. X    }
  845. X    putreg(fp, curbuf->b_first, 0, curbuf->b_last, length(curbuf->b_last), NO);
  846. X    set_ino(curbuf);
  847. X    close_file(fp);
  848. X}
  849. X
  850. void
  851. ReadFile()
  852. X{
  853. X    Buffer    *bp;
  854. X    char    *fname,
  855. X        fnamebuf[FILESIZE];
  856. X    int    lineno;
  857. X
  858. X#ifdef MAC
  859. X    if(Macmode) {
  860. X        if(!(fname = gfile(fnamebuf))) return;
  861. X    }
  862. X    else
  863. X#endif /* MAC */
  864. X    fname = ask_file((char *) 0, curbuf->b_fname, fnamebuf);
  865. X#ifndef MAC
  866. X#ifndef MSDOS
  867. X    chk_mtime(curbuf, fname, "read");
  868. X#endif /* MSDOS */
  869. X#endif /* MAC */
  870. X
  871. X    if (IsModified(curbuf)) {
  872. X        char    *y_or_n;
  873. X        int    c;
  874. X
  875. X        for (;;) {
  876. X            rbell();
  877. X            y_or_n = ask(NullStr, "Shall I make your changes to \"%s\" permanent? ", curbuf->b_name);
  878. X            c = CharUpcase(*y_or_n);
  879. X            if (c == 'Y' || c == 'N')
  880. X                break;
  881. X        }            
  882. X        if (c == 'Y')
  883. X            SaveFile();
  884. X    }
  885. X
  886. X    if ((bp = file_exists(fnamebuf)) &&
  887. X        (bp == curbuf))
  888. X        lineno = pnt_line() - 1;
  889. X    else
  890. X        lineno = 0;
  891. X
  892. X    unmodify();
  893. X    initlist(curbuf);
  894. X    setfname(curbuf, fname);
  895. X    read_file(fname, 0);
  896. X    SetLine(next_line(curbuf->b_first, lineno));
  897. X}
  898. X
  899. void
  900. InsFile()
  901. X{
  902. X    char    *fname,
  903. X        fnamebuf[FILESIZE];
  904. X#ifdef MAC
  905. X    if(Macmode) {
  906. X        if(!(fname = gfile(fnamebuf))) return;
  907. X    }
  908. X    else
  909. X#endif /* MAC */
  910. X    fname = ask_file((char *) 0, curbuf->b_fname, fnamebuf);
  911. X    read_file(fname, 1);
  912. X}
  913. X
  914. X#include "temp.h"
  915. X
  916. int    DOLsave = 0;    /* Do Lsave flag.  If lines aren't being save
  917. X               when you think they should have been, this
  918. X               flag is probably not being set, or is being
  919. X               cleared before lsave() was called. */
  920. X
  921. private int    nleft,    /* number of good characters left in current block */
  922. X        tmpfd = -1;
  923. disk_line    DFree = 1;
  924. X            /* pointer to end of tmp file */
  925. private char    *tfname;
  926. X
  927. void
  928. tmpinit()
  929. X{
  930. X    char    buf[FILESIZE];
  931. X
  932. X#ifdef MAC
  933. X    sprintf(buf, "%s/%s", HomeDir, d_tempfile);
  934. X#else
  935. X    sprintf(buf, "%s/%s", TmpFilePath, d_tempfile);
  936. X#endif
  937. X    tfname = copystr(buf);
  938. X    tfname = mktemp(tfname);
  939. X    (void) close(creat(tfname, 0600));
  940. X#ifndef MSDOS
  941. X    tmpfd = open(tfname, 2);
  942. X#else /* MSDOS */
  943. X    tmpfd = open(tfname, 0x8002);    /* MSDOS fix    */
  944. X#endif /* MSDOS */
  945. X    if (tmpfd == -1)
  946. X        complain("Warning: cannot create tmp file!");
  947. X}
  948. X
  949. void
  950. tmpclose()
  951. X{
  952. X    if (tmpfd == -1)
  953. X        return;
  954. X    (void) close(tmpfd);
  955. X    tmpfd = -1;
  956. X    (void) unlink(tfname);
  957. X}
  958. X
  959. X/* get a line at `tl' in the tmp file into `buf' which should be LBSIZE
  960. X   long */
  961. X
  962. int    Jr_Len;        /* length of Just Read Line */
  963. X
  964. X#ifdef MAC    /* The Lighspeed compiler can't copy with static here */
  965. X    char    *getblock();
  966. X#else
  967. private char    *getblock();
  968. X#endif
  969. void
  970. getline(addr, buf)
  971. disk_line    addr;
  972. register char    *buf;
  973. X{
  974. X    register char    *bp,
  975. X            *lp;
  976. X
  977. X    lp = buf;
  978. X    bp = getblock(addr >> 1, READ);
  979. X    while (*lp++ = *bp++)
  980. X        ;
  981. X    Jr_Len = (lp - buf) - 1;
  982. X}
  983. X
  984. X/* Put `buf' and return the disk address */
  985. X
  986. disk_line
  987. putline(buf)
  988. char    *buf;
  989. X{
  990. X    register char    *bp,
  991. X            *lp;
  992. X    register int    nl;
  993. X    disk_line    free_ptr;
  994. X
  995. X    lp = buf;
  996. X    free_ptr = DFree;
  997. X    bp = getblock(free_ptr, WRITE);
  998. X    nl = nleft;
  999. X    free_ptr = blk_round(free_ptr);
  1000. X    while (*bp = *lp++) {
  1001. X        if (*bp++ == '\n') {
  1002. X            *--bp = 0;
  1003. X            break;
  1004. X        }
  1005. X        if (--nl == 0) {
  1006. X            free_ptr = forward_block(free_ptr);
  1007. X            DFree = free_ptr;
  1008. X            bp = getblock(free_ptr, WRITE);
  1009. X            lp = buf;    /* start over ... */
  1010. X            nl = nleft;
  1011. X        }
  1012. X    }
  1013. X    free_ptr = DFree;
  1014. X    DFree += (((lp - buf) + CH_SIZE - 1) / CH_SIZE);
  1015. X             /* (lp - buf) includes the null */
  1016. X    return (free_ptr << 1);
  1017. X}
  1018. X
  1019. X/* The theory is that critical section of code inside this procedure
  1020. X   will never cause a problem to occur.  Basically, we need to ensure
  1021. X   that two blocks are in memory at the same time, but I think that
  1022. X   this can never screw up. */
  1023. X
  1024. X#define lockblock(addr)
  1025. X#define unlockblock(addr)
  1026. X
  1027. disk_line
  1028. f_getputl(line, fp)
  1029. Line    *line;
  1030. register File    *fp;
  1031. X{
  1032. X    register char    *bp;
  1033. X    register int    c,
  1034. X            nl,
  1035. X            max = LBSIZE;
  1036. X    disk_line    free_ptr;
  1037. X    char        *base;
  1038. X#ifdef MSDOS
  1039. X    char crleft = 0;
  1040. X#endif /* MSDOS */
  1041. X
  1042. X    free_ptr = DFree;
  1043. X    base = bp = getblock(free_ptr, WRITE);
  1044. X    nl = nleft;
  1045. X    free_ptr = blk_round(free_ptr);
  1046. X    while (--max > 0) {
  1047. X#ifdef MSDOS
  1048. X        if (crleft) {
  1049. X           c = crleft;
  1050. X           crleft = 0;
  1051. X        } else
  1052. X#endif /* MSDOS */
  1053. X        c = getc(fp);
  1054. X        if (c == EOF || c == '\n')
  1055. X            break;
  1056. X#ifdef MSDOS
  1057. X        if (c == '\r') 
  1058. X            if ((crleft = getc(fp)) == '\n') {
  1059. X                crleft = 0;
  1060. X                break;
  1061. X            }
  1062. X#endif /* MSDOS */
  1063. X        if (--nl == 0) {
  1064. X            char    *newbp;
  1065. X            int    nbytes;
  1066. X
  1067. X            lockblock(free_ptr);
  1068. X            DFree = free_ptr = forward_block(free_ptr);
  1069. X            nbytes = bp - base;
  1070. X            newbp = getblock(free_ptr, WRITE);
  1071. X            nl = nleft;
  1072. X            byte_copy(base, newbp, nbytes);
  1073. X            bp = newbp + nbytes;
  1074. X            base = newbp;
  1075. X            unlockblock(free_ptr);
  1076. X        }
  1077. X        *bp++ = c;
  1078. X    }
  1079. X    *bp++ = '\0';
  1080. X    free_ptr = DFree;
  1081. X    DFree += (((bp - base) + CH_SIZE - 1) / CH_SIZE);
  1082. X    line->l_dline = (free_ptr << 1);
  1083. X    if (max == 0) {
  1084. X        add_mess(" [Line too long]");
  1085. X        rbell();
  1086. X        return EOF;
  1087. X    }
  1088. X    if (c == EOF) {
  1089. X        if (--bp != base)
  1090. X            add_mess(" [Incomplete last line]");
  1091. X        return EOF;
  1092. X    }
  1093. X    io_lines += 1;
  1094. X    return 0;
  1095. X}
  1096. X
  1097. typedef struct block {
  1098. X    short    b_dirty,
  1099. X        b_bno;
  1100. X    char    b_buf[BUFSIZ];
  1101. X    struct block
  1102. X        *b_LRUnext,
  1103. X        *b_LRUprev,
  1104. X        *b_HASHnext;
  1105. X} Block;
  1106. X
  1107. X#define HASHSIZE    7    /* Primes work best (so I'm told) */
  1108. X#define B_HASH(bno)    (bno % HASHSIZE)
  1109. X
  1110. X#ifdef MAC
  1111. private Block    *b_cache,
  1112. X#else
  1113. private Block    b_cache[NBUF],
  1114. X#endif
  1115. X        *bht[HASHSIZE] = {0},        /* Block hash table */
  1116. X        *f_block = 0,
  1117. X        *l_block = 0;
  1118. private int    max_bno = -1,
  1119. X        NBlocks;
  1120. X
  1121. X#ifdef MAC
  1122. void (*blkio)();
  1123. X#else
  1124. X#ifdef LINT_ARGS
  1125. private int    (*blkio)(Block *, int (*)());
  1126. X#else
  1127. private int (*blkio)();
  1128. X#endif
  1129. X#endif /* MAC */
  1130. X
  1131. X#ifdef MAC
  1132. make_cache()    /* Only 32K of static space on Mac, so... */
  1133. X{
  1134. X    return((b_cache = (Block *) calloc(NBUF,sizeof(Block))) == 0 ? 0 : 1);
  1135. X}
  1136. X#endif /* MAC */
  1137. X
  1138. extern int read(), write();
  1139. X
  1140. private void
  1141. real_blkio(b, iofcn)
  1142. register Block    *b;
  1143. X#ifdef LINT_ARGS
  1144. register int    (*iofcn)(int, char *, unsigned int);
  1145. X#else
  1146. register int    (*iofcn)();
  1147. X#endif
  1148. X{
  1149. X    (void) lseek(tmpfd, (long) ((unsigned) b->b_bno) * BUFSIZ, 0);
  1150. X    if ((*iofcn)(tmpfd, b->b_buf, BUFSIZ) != BUFSIZ)
  1151. X        error("[Tmp file %s error; to continue editing would be dangerous]", (iofcn == read) ? "READ" : "WRITE");
  1152. X}
  1153. X
  1154. private void
  1155. fake_blkio(b, iofcn)
  1156. register Block    *b;
  1157. register int    (*iofcn)();
  1158. X{
  1159. X    tmpinit();
  1160. X    blkio = real_blkio;
  1161. X    real_blkio(b, iofcn);
  1162. X}
  1163. X
  1164. void
  1165. d_cache_init()
  1166. X{
  1167. X    register Block    *bp,    /* Block pointer */
  1168. X            **hp;    /* Hash pointer */
  1169. X    register short    bno;
  1170. X
  1171. X    for (bp = b_cache, bno = NBUF; --bno >= 0; bp++) {
  1172. X        NBlocks += 1;
  1173. X        bp->b_dirty = 0;
  1174. X        bp->b_bno = bno;
  1175. X        if (l_block == 0)
  1176. X            l_block = bp;
  1177. X        bp->b_LRUprev = 0;
  1178. X        bp->b_LRUnext = f_block;
  1179. X        if (f_block != 0)
  1180. X            f_block->b_LRUprev = bp;
  1181. X        f_block = bp;
  1182. X
  1183. X        bp->b_HASHnext = *(hp = &bht[B_HASH(bno)]);
  1184. X        *hp = bp;
  1185. X    }
  1186. X    blkio = fake_blkio;
  1187. X}
  1188. X
  1189. void
  1190. SyncTmp()
  1191. X{
  1192. X    register Block    *b;
  1193. X#ifdef IBMPC
  1194. X    register int    bno = 0;
  1195. X    Block    *lookup();
  1196. X
  1197. X    /* sync the blocks in order, for floppy disks */
  1198. X    for (bno = 0; bno <= max_bno; ) {
  1199. X        if ((b = lookup(bno++)) && b->b_dirty) {
  1200. X            (*blkio)(b, write);
  1201. X            b->b_dirty = 0;
  1202. X        }
  1203. X    }
  1204. X#else
  1205. X    for (b = f_block; b != 0; b = b->b_LRUnext)
  1206. X        if (b->b_dirty) {
  1207. X            (*blkio)(b, write);
  1208. X            b->b_dirty = 0;
  1209. X        }
  1210. X#endif
  1211. X}
  1212. X
  1213. private Block *
  1214. lookup(bno)
  1215. register short    bno;
  1216. X{
  1217. X    register Block    *bp;
  1218. X
  1219. X    for (bp = bht[B_HASH(bno)]; bp != 0; bp = bp->b_HASHnext)
  1220. X        if (bp->b_bno == bno)
  1221. X            break;
  1222. X    return bp;
  1223. X}
  1224. X
  1225. private void
  1226. LRUunlink(b)
  1227. register Block    *b;
  1228. X{
  1229. X    if (b->b_LRUprev == 0)
  1230. X        f_block = b->b_LRUnext;
  1231. X    else
  1232. X        b->b_LRUprev->b_LRUnext = b->b_LRUnext;
  1233. X    if (b->b_LRUnext == 0)
  1234. X        l_block = b->b_LRUprev;
  1235. X    else
  1236. X        b->b_LRUnext->b_LRUprev = b->b_LRUprev;
  1237. X}
  1238. X
  1239. private Block *
  1240. b_unlink(bp)
  1241. register Block    *bp;
  1242. X{
  1243. X    register Block    *hp,
  1244. X            *prev = 0;
  1245. X
  1246. X    LRUunlink(bp);
  1247. X    /* Now that we have the block, we remove it from its position
  1248. X       in the hash table, so we can THEN put it somewhere else with
  1249. X       it's new block assignment. */
  1250. X
  1251. X    for (hp = bht[B_HASH(bp->b_bno)]; hp != 0; prev = hp, hp = hp->b_HASHnext)
  1252. X        if (hp == bp)
  1253. X            break;
  1254. X    if (hp == 0) {
  1255. X        printf("\rBlock %d missing!", bp->b_bno);
  1256. X        finish(0);
  1257. X    }
  1258. X    if (prev)
  1259. X        prev->b_HASHnext = hp->b_HASHnext;
  1260. X    else
  1261. X        bht[B_HASH(bp->b_bno)] = hp->b_HASHnext;
  1262. X
  1263. X    if (bp->b_dirty) {    /* do, now, the delayed write */
  1264. X        (*blkio)(bp, write);
  1265. X        bp->b_dirty = 0;
  1266. X    }
  1267. X
  1268. X    return bp;
  1269. X}
  1270. X
  1271. X/* Get a block which contains at least part of the line with the address
  1272. X   atl.  Returns a pointer to the block and sets the global variable
  1273. X   nleft (number of good characters left in the buffer). */
  1274. X
  1275. private char *
  1276. getblock(atl, iof)
  1277. disk_line    atl;
  1278. X{
  1279. X    register int    bno,
  1280. X            off;
  1281. X    register Block    *bp;
  1282. X    static Block    *lastb = 0;
  1283. X
  1284. X    bno = da_to_bno(atl);
  1285. X    off = da_to_off(atl);
  1286. X    if (da_too_huge(atl))
  1287. X        error("Tmp file too large.  Get help!");
  1288. X    nleft = BUFSIZ - off;
  1289. X    if (lastb != 0 && lastb->b_bno == bno) {
  1290. X        lastb->b_dirty |= iof;
  1291. X        return lastb->b_buf + off;
  1292. X    }
  1293. X
  1294. X    /* The requested block already lives in memory, so we move
  1295. X       it to the end of the LRU list (making it Most Recently Used)
  1296. X       and then return a pointer to it. */
  1297. X    if (bp = lookup(bno)) {
  1298. X        if (bp != l_block) {
  1299. X            LRUunlink(bp);
  1300. X            if (l_block == 0)
  1301. X                f_block = l_block = bp;
  1302. X            else
  1303. X                l_block->b_LRUnext = bp;
  1304. X            bp->b_LRUprev = l_block;
  1305. X            l_block = bp;
  1306. X            bp->b_LRUnext = 0;
  1307. X        }
  1308. X        if (bp->b_bno > max_bno)
  1309. X            max_bno = bp->b_bno;
  1310. X        bp->b_dirty |= iof;
  1311. X        lastb = bp;
  1312. X        return bp->b_buf + off;
  1313. X    }
  1314. X
  1315. X    /* The block we want doesn't reside in memory so we take the
  1316. X       least recently used clean block (if there is one) and use
  1317. X       it.  */
  1318. X    bp = f_block;
  1319. X    if (bp->b_dirty)    /* The best block is dirty ... */
  1320. X        SyncTmp();
  1321. X
  1322. X    bp = b_unlink(bp);
  1323. X    if (l_block == 0)
  1324. X        l_block = f_block = bp;
  1325. X    else
  1326. X        l_block->b_LRUnext = bp;    /* Place it at the end ... */
  1327. X    bp->b_LRUprev = l_block;
  1328. X    l_block = bp;
  1329. X    bp->b_LRUnext = 0;        /* so it's Most Recently Used */
  1330. X
  1331. X    bp->b_dirty = iof;
  1332. X    bp->b_bno = bno;
  1333. X    bp->b_HASHnext = bht[B_HASH(bno)];
  1334. X    bht[B_HASH(bno)] = bp;
  1335. X
  1336. X    /* Get the current contents of the block UNLESS this is a new
  1337. X       block that's never been looked at before, i.e., it's past
  1338. X       the end of the tmp file. */
  1339. X
  1340. X    if (bp->b_bno <= max_bno)
  1341. X        (*blkio)(bp, read);
  1342. X    else
  1343. X        max_bno = bno;
  1344. X
  1345. X    lastb = bp;
  1346. X    return bp->b_buf + off;
  1347. X}
  1348. X
  1349. char *
  1350. lbptr(line)
  1351. Line    *line;
  1352. X{
  1353. X    return getblock(line->l_dline >> 1, READ);
  1354. X}
  1355. X
  1356. X/* save the current contents of linebuf, if it has changed */
  1357. X
  1358. void
  1359. lsave()
  1360. X{
  1361. X    if (curbuf == 0 || !DOLsave)    /* Nothing modified recently */
  1362. X        return;
  1363. X
  1364. X    if (strcmp(lbptr(curline), linebuf) != 0)
  1365. X        SavLine(curline, linebuf);    /* Put linebuf on the disk. */
  1366. X    DOLsave = 0;
  1367. X}
  1368. X
  1369. X#ifdef BACKUPFILES
  1370. void
  1371. file_backup(fname)
  1372. char *fname;
  1373. X{
  1374. X#ifndef MSDOS
  1375. X    char    *s;
  1376. X    register int    i;
  1377. X    int    fd1,
  1378. X        fd2;
  1379. X    char    tmp1[BUFSIZ],
  1380. X        tmp2[BUFSIZ];
  1381. X     struct stat buf;
  1382. X     int    mode;
  1383. X
  1384. X    strcpy(tmp1, fname);
  1385. X    if ((s = rindex(tmp1, '/')) == NULL)
  1386. X        sprintf(tmp2, "#%s", fname);
  1387. X    else {
  1388. X        *s++ = '\0';
  1389. X        sprintf(tmp2, "%s/#%s", tmp1, s);
  1390. X    }
  1391. X
  1392. X    if ((fd1 = open(fname, 0)) < 0)
  1393. X        return;
  1394. X
  1395. X    /* create backup file with same mode as input file */
  1396. X#ifndef MAC
  1397. X    if (fstat(fd1, &buf) != 0)
  1398. X        mode = CreatMode;
  1399. X    else
  1400. X#endif
  1401. X        mode = buf.st_mode;
  1402. X        
  1403. X    if ((fd2 = creat(tmp2, mode)) < 0) {
  1404. X        (void) close(fd1);
  1405. X        return;
  1406. X    }
  1407. X    while ((i = read(fd1, tmp1, sizeof(tmp1))) > 0)
  1408. X        write(fd2, tmp1, i);
  1409. X#ifdef BSD4_2
  1410. X    (void) fsync(fd2);
  1411. X#endif
  1412. X    (void) close(fd2);
  1413. X    (void) close(fd1);
  1414. X#else /* MSDOS */
  1415. X    char    *dot,
  1416. X            *slash,
  1417. X            tmp[FILESIZE];
  1418. X    
  1419. X    strcpy(tmp, fname);
  1420. X    slash = basename(tmp);
  1421. X    if (dot = rindex(slash, '.')) {
  1422. X       if (!stricmp(dot,".bak")) 
  1423. X        return;
  1424. X       else *dot = 0;
  1425. X    }
  1426. X    strcat(tmp, ".bak");
  1427. X    unlink(tmp);
  1428. X    rename(fname, tmp);
  1429. X#endif /* MSDOS */
  1430. X}
  1431. X#endif
  1432. X
  1433. X#if defined(MSDOS) && defined (CHDIR)
  1434. X
  1435. private int            /* chdir + drive */
  1436. Dchdir(to)
  1437. char *to;
  1438. X{
  1439. X    unsigned d, dd, n;
  1440. X    
  1441. X    if (to[1] == ':') {
  1442. X        d = to[0];
  1443. X        if (d >= 'a') d = d - 'a' + 1;
  1444. X        if (d >= 'A') d = d - 'A' + 1;
  1445. X        _dos_getdrive(&dd);
  1446. X        if (dd != d)
  1447. X            _dos_setdrive(d, &n);
  1448. X        if (to[2] == 0)
  1449. X            return 0;
  1450. X    }
  1451. X    return chdir(to);
  1452. X}
  1453. X
  1454. private char *
  1455. fixpath(p)
  1456. char *p;
  1457. X{
  1458. X    char *pp = p;
  1459. X
  1460. X    while (*p) {
  1461. X        if (*p == '\\')
  1462. X            *p = '/';
  1463. X        p++;
  1464. X    }
  1465. X    return(strlwr(pp));
  1466. X}
  1467. X    
  1468. X
  1469. private void
  1470. abspath(so, dest)
  1471. char *so, *dest;
  1472. X{
  1473. X    char cwd[FILESIZE], cwdD[3], cwdDIR[FILESIZE], cwdF[9], cwdEXT[5],
  1474. X         soD[3], soDIR[FILESIZE], soF[9], soEXT[5];
  1475. X    char *drive, *path;
  1476. X
  1477. X    _splitpath(fixpath(so), soD, soDIR, soF, soEXT);
  1478. X    getcwd(cwd, FILESIZE);
  1479. X    if (*soD != 0) {
  1480. X        Dchdir(soD);                /* this is kinda messy    */
  1481. X        getcwd(cwdDIR, FILESIZE);    /* should probably just    */
  1482. X        Dchdir(cwd);                /* call DOS to do it    */
  1483. X        strcpy(cwd, cwdDIR);
  1484. X    }
  1485. X    (void) fixpath(cwd);
  1486. X    if (cwd[strlen(cwd)-1] != '/')
  1487. X        strcat(cwd, "/x.x");    /* need dummy filename */
  1488. X
  1489. X    _splitpath(fixpath(cwd), cwdD, cwdDIR, cwdF, cwdEXT);
  1490. X
  1491. X    drive = (*soD == 0) ? cwdD : soD;
  1492. X        
  1493. X    if (*soDIR != '/')
  1494. X        path = strcat(cwdDIR, soDIR);
  1495. X    else
  1496. X        path = soDIR;
  1497. X    _makepath(dest, drive, path, soF, soEXT);
  1498. X    fixpath(dest);    /* can't do it often enough */
  1499. X}
  1500. X
  1501. X#endif
  1502. END_OF_FILE
  1503. if test 28324 -ne `wc -c <'./io.c'`; then
  1504.     echo shar: \"'./io.c'\" unpacked with wrong size!
  1505. fi
  1506. # end of './io.c'
  1507. fi
  1508. echo shar: End of archive 12 \(of 21\).
  1509. cp /dev/null ark12isdone
  1510. MISSING=""
  1511. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 ; do
  1512.     if test ! -f ark${I}isdone ; then
  1513.     MISSING="${MISSING} ${I}"
  1514.     fi
  1515. done
  1516. if test "${MISSING}" = "" ; then
  1517.     echo You have unpacked all 21 archives.
  1518.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1519. else
  1520.     echo You still need to unpack the following archives:
  1521.     echo "        " ${MISSING}
  1522. fi
  1523. ##  End of shell archive.
  1524. exit 0
  1525.